package com.tinyproxy.remote;

import com.tinyproxy.common.Cfg;
import com.tinyproxy.common.Kits;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RemoteServer extends Thread {

    final Cfg cfg;

    private static final String BANNER = """
             
             
             /__  ___/                     //   ) )
               / /  ( )   __              ((         ___      __              ___      __
              / /  / / //   ) ) //   / /    \\\\     //___) ) //  ) ) ||  / / //___) ) //  ) )
             / /  / / //   / / ((___/ /       ) ) //       //       || / / //       //
            / /  / / //   / /      / / ((___ / / ((____   //        ||/ / ((____   //
                            
            %s
            """;

    public RemoteServer(Cfg cfg, Logger log) {
        this.cfg = cfg;
        log.info(BANNER.formatted(cfg));
    }

    @Override
    public void run() {
        final Logger log = LoggerFactory.getLogger(getClass());
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        NioEventLoopGroup worker = new NioEventLoopGroup(Kits.CPU_COUNT * 2);
        ServerBootstrap bootstrap = new ServerBootstrap().group(boss, worker);
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.childOption(ChannelOption.SO_SNDBUF, 16 * 1024);
        bootstrap.childOption(ChannelOption.SO_RCVBUF, 16 * 1024);
        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel ch) {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new RemoteDecoder(cfg));
            }

        });

        try {
            ChannelFuture future = bootstrap.bind(cfg.getRemotePort()).sync();

            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("Netty abnormally exit!", e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

}
